#ifndef atomic_h__
#define atomic_h__
#include <windows.h>

namespace gecko
{

	namespace Atomic
	{

		// Atomic increment of value at address 'ptr'.
		static inline void Increment(volatile int* ptr)
		{
			InterlockedIncrement((LONG volatile*)ptr);
		}

		// Atomic decrement of value at address 'ptr'.
		static inline int Decrement(volatile int* ptr)
		{
			return (int)InterlockedDecrement((LONG volatile*)ptr);
		}

		// Compare two values and swap - 32bit version.
		static inline bool CompareSwap(volatile long* ptr, long compare, long swap)
		{
#pragma warning(disable:4311)
#pragma warning(disable:4312)
			return InterlockedCompareExchange(ptr, (LONG)swap, (LONG)compare) == compare;
#pragma warning(default:4311)
#pragma warning(default:4312)
		}

		// Compare two values and swap - 64bit version.
		static inline bool CompareSwap(volatile long long* ptr, long long compare, long long swap)
		{
#pragma warning(disable:4311)
#pragma warning(disable:4312)
			return InterlockedCompareExchange64(ptr, (LONGLONG)swap, (LONGLONG)compare) == compare;
#pragma warning(default:4311)
#pragma warning(default:4312)
		}

		// Compare two pointers and swap.
		static inline bool CompareSwapPtr(volatile void** ptr, const void* compare, const void* swap)
		{
#if defined(__x86)
			return Atomic::CompareSwap((volatile long*)ptr, (long)compare, (long)swap);
#elif defined(__x64)
			return Atomic::CompareSwap((volatile long long*)ptr, (long long)compare, (long long)swap);
#endif
		}

		// Add a value to another without needing to protect with critical sections.
		static inline void Add(unsigned int* ptr, unsigned int value)
		{
			InterlockedExchangeAdd((LONG volatile*)ptr, (LONG)value);
		}

		// Subtract a value from another without needing to protect with critical sections.
		static inline void Subtract(unsigned int* ptr, unsigned int value)
		{
			InterlockedExchangeAdd((LONG volatile*)ptr, -(LONG)value);
		}

		// Add a value to another without needing to protect with critical sections.
		static inline void Add(unsigned long* ptr, unsigned long value)
		{
			InterlockedExchangeAdd((LONG volatile*)ptr, (LONG)value);
		}

		// Subtract a value from another without needing to protect with critical sections.
		static inline void Subtract(unsigned long* ptr, unsigned long value)
		{
			InterlockedExchangeAdd((LONG volatile*)ptr, -(LONG)value);
		}

		// Add a value to another without needing to protect with critical sections.
		static inline void Add(unsigned long long* ptr, unsigned long long value)
		{
			InterlockedExchangeAdd64((LONGLONG volatile*)ptr, (LONGLONG)value);
		}

		// Subtract a value from another without needing to protect with critical sections.
		static inline void Subtract(unsigned long long* ptr, unsigned long long value)
		{
			InterlockedExchangeAdd64((LONGLONG volatile*)ptr, -(LONGLONG)value);
		}

	}

} // namespace gecko

#endif // atomic_h__